package shortcircuit.basics;

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.HashMap;

/**
 * This class will hold the two-dimensional array of cells.<p>
 * 
 * @author Kevin Lewi
 */

public class Environment implements Element
{
	static final int CELLSIZE = 40;
	private Cell[][] _Grid;
	private HashMap<Cell, Point> hashedGrid;
	
	Cell transparentCell;
	int cellColumn;
	
	/**
	 * Creates the grid with the specified grid dimensions.
	 * 
	 * @param theGridDimensions The width and height of the grid
	 * @author Kevin Lewi
	 */
	public Environment(Dimension theGridDimensions)
	{
		_Grid = new Cell[(int) theGridDimensions.getWidth()][(int) theGridDimensions.getHeight()];

		hashedGrid = new HashMap<Cell, Point>();
		for(int x = 0; x < _Grid.length; x++)
		{
			for(int y = 0; y < _Grid[0].length; y++)
			{
				_Grid[x][y] = new Cell();
				hashedGrid.put(_Grid[x][y], new Point(x, y));
			}
		}
	}
	
	/**
	 * Sets the values for the transparent image of the moving block and the
	 * column of the mouse cursor to be drawn in.
	 * 
	 * @param theTransparentCell The cell that is to be replicated transparently
	 * @param theCol The column in which this transparent cell will be displayed in
	 * @author Kevin Lewi
	 */
	public void setTransparentCell(Cell theTransparentCell, int theCol)
	{
		transparentCell = theTransparentCell;
		cellColumn = theCol;
	}
	
	/**
	 * Puts cells together by taking the Graphics elements from each.  The graphics will reverse the order of the blocks
	 * in order to be displayed correctly.
	 * 
	 * @author Kevin Lewi
	 */
	public void getGraphics(Graphics g)
	{
		
		for(int y = 0; y < _Grid[0].length; y++)
		{
			for(int x = 0; x < _Grid.length; x++)
			{
				_Grid[x][y].getGraphics(g);
				g.translate(CELLSIZE, 0);
			}
			g.translate(-CELLSIZE * _Grid.length, -CELLSIZE);
		}
		//g.translate(0, _Grid[0].length * CELLSIZE);
	}
	
	/**
	 * Replaces the contents of a cell in the internal environment grid.
	 * Adding occurs by stacking rows on top of one another from left to right.
	 * 
	 * @param cellNumber The number of the cell assigned by position
	 * @param theNewBlock The block to be added to the cell
	 * @author Kevin Lewi
	 */
	public void replaceCellContents(int cellNumber, int theBlockNumber)
	{
		try
		{
			String className = "shortcircuit.basics.block.Block" + theBlockNumber;
			Block theNewBlock = (Block) Class.forName(className).newInstance();
			Cell theTargettedCell = getCell(cellNumber);
			if(theTargettedCell == null)
				theTargettedCell = new Cell();
			theTargettedCell.removeBlock();
			theTargettedCell.setBlock(theNewBlock);
		}
		catch(ClassNotFoundException e) { System.out.println("Error: Class Not Found Exception"); }
		catch(InstantiationException e) { System.out.println("Error: Instantiation Exception"); }
		catch(IllegalAccessException e) { System.out.println("Error: Illegal Access Exception"); }
	}
	
	/**
	 * Replaces the contents of a cell in the internal environment grid.
	 * Adding occurs by stacking rows on top of one another from left to right.
	 * 
	 * @param theTargettedCell The Cell to be replaced
	 * @param theNewBlock The block to be added to the cell
	 * @author David Li
	 */
	public void replaceCellContents(Cell theTargettedCell, Block theNewBlock)
	{
		if(theTargettedCell == null)
			theTargettedCell = new Cell();
		theTargettedCell.removeBlock();
		theTargettedCell.setBlock(theNewBlock);
	}
	
	/**
	 * Removes all contents currently in the cell, whether or not there was a block there
	 * in the first place.
	 * 
	 * @param theTargettedCell The cell to be modified
	 * @author Kevin Lewi
	 */
	public boolean clearCell(Cell theTargettedCell)
	{
		if(!theTargettedCell.hasBlock())
			return false;
		theTargettedCell.removeBlock();
		return true;
	}
	
	/**
	 * Returns the cell in the grid with the specified row and column
	 * coordinates.
	 * 
	 * @param x The x coordinate
	 * @param y The y coordinate
	 * @return The appropriate cell
	 * @author Kevin Lewi
	 */
	public Cell getCell(int x, int y)
	{
		if(x >= 0 && y >= 0 && x < _Grid.length && y < _Grid[0].length)
			return _Grid[x][y];
		else
			return null;
	}
	
	public void setCell(int x, int y, Block theBlock){
		if(x >= 0 && y >= 0 && x < _Grid.length && y < _Grid[0].length)
			_Grid[x][y].setBlock(theBlock);
	}
	
	/**
	 * Returns the location of the cell in the environment using the hashed grid representation
	 * of the environment.
	 * 
	 * @param theCell
	 * @return The correct cell location
	 * @author Kevin Lewi
	 */
	public Point getLocation(Cell theCell)
	{
		return hashedGrid.get(theCell);
	}
	
	/**
	 * Returns the cell in the grid with the specified cell number.
	 * 
	 * @param cellNumber The assigned number to the cell
	 * @return The appropriate cell
	 * @author Kevin Lewi
	 */
	public Cell getCell(int cellNumber)
	{
		return _Grid[cellNumber % _Grid.length][cellNumber / _Grid.length];
	}
	
	/**
	 * Returns the single integer number of the cell by calculating from its location.
	 * 
	 * @param theCell The cell to be analyzed
	 * @return The corresponding cell number to the parameterized cell
	 * @author Kevin Lewi
	 */
	public int getCellNumber(Cell theCell)
	{
		Point cellLocation = getLocation(theCell);
		return (int) (cellLocation.getX() * 10 + cellLocation.getY());
	}
	
	/**
	 * This method will return the two-dimensional array of cells stored by the class.
	 * 
	 * @return The grid composed of a two dimensional array of cells
	 * @author Kevin Lewi
	 */
	public Cell[][] getGrid()
	{
		return _Grid;
	}
}
